using Game.Networking;
using Game.Networking.Server;
using System.Collections.Generic;
using UnityEngine;

namespace Game {
	public partial class CargoContainer : WorldEntity<CargoContainerState>, IDamageReceiver {
		public TeamType Team = TeamType.Neutral;
		public float SelfDestructTime = -1;
		public uint CreatorID;
		BaseInventory		   _inventory;
		InventoryItemPresenter _presenter;

		double _setupTime;

		public override EntityType EntityType => EntityType.CargoContainer;


		public static CargoContainer SpawnFromPayload(Vector3 position, Vector3 rotation, List<BaseInventoryItem> payload) {
			var result = ServerEntityController.Instance.CreateNewEntity(EntityType.CargoContainer, position, rotation, e => {
				var cast = (CargoContainer)e;
				cast.Setup(payload);
			});
			return (CargoContainer)result;
		}

		public void Setup(List<BaseInventoryItem> items) {
			_inventory = new BaseInventory(items?.Count ?? 0);
			_inventory.AddItems(items);
			Setup(_inventory);

		}

		void Setup(BaseInventory inventory) {
			if ( _presenter ) {
				_presenter.Kill();
			}
			_inventory = inventory;
			_presenter = inventory.SlotCount == 0 || inventory.SlotCount > 1 ? ItemWorldPresenterPool.Instance.CreateCargoBoxItemPresenter() : inventory.GetItemInSlot(0).CreatePresenter();
			_presenter.transform.parent = transform;
			_presenter.transform.localPosition = Vector3.zero;
			_setupTime = GameManager.Instance.IsServer ? ServerGameManager.Time : ClientGameManager.Time;
		}

		public void ApplyDamage(DamageDescription damage) {
			if ( damage.Damage < 1 ) {
				return;
			}
			if ( !CommonStaticData.CanDealDamage(damage.AttackerTeam, Team) ) {
				return;
			}
			if ( IsServer ) {
				DestroyEntity();
			}
		}

		public bool Collect(BaseInventory receiver, Vector3 collectorPos) {
			var result = CollectInternal(receiver, out var shouldDestroy);
			if ( shouldDestroy ) {
				if ( IsServer ) {
					DestroyEntity();
					if ( collectorPos.magnitude > 0.1f ) {
						S_CallRPC_CollectToPosition(collectorPos, true);
					}
				}
			}
			return result;
		}

		public bool Collect(BaseInventory receiver, uint collectorEntity) {
			var result = CollectInternal(receiver, out var shouldDestroy);
			if ( shouldDestroy ) {
				if ( IsServer ) {
					DestroyEntity();
					if ( collectorEntity > 0 ) {
						S_CallRPC_CollectToEntityPos(collectorEntity, true);
					}
				}
			}
			return result;
		}

		public void FakeCollect(Vector3 collectPos) {
			if ( IsServer ) {
				DestroyEntity();
				S_CallRPC_CollectToPosition(collectPos, true);
			}
		}

		public int GetTotalPrice() {
			return _inventory.GetWholeInventoryPrice();
		}

		bool CollectInternal(BaseInventory receiver, out bool shouldDestroy) {
			_summary = null;
			shouldDestroy = false;
			if ( receiver == null ) {
				return false;
			}
			if ( !receiver.AddItems(_inventory.Items) ) {
				return false;
			}
			if ( _inventory.ItemCount == 0 ) {
				shouldDestroy = true;
			}
			return true;
		}

		[ClientRPC(16)]
		void CollectToPosition(Vector3 position) {
			if ( _presenter != null ) {
				_presenter.transform.SetParent(null, true);
				_ = _presenter.MoveToPointAndKill(position, 0.75f);
			}
		}

		[ClientRPC(17)]
		void CollectToEntityPos(uint entityId) {
			if ( _presenter == null ) {
				return;
			}
			var ec = GameManager.Instance.GetLocalEntityController();
			if ( ec == null ) {
				return;
			}
			var targetE = ec.GetEntityById(entityId);
			if ( targetE == null ) {
				return;
			}
			var syncTr = (ISyncTransform)targetE;
			if ( syncTr == null ) {
				return;
			}
			_presenter.transform.SetParent(null, true);
			_ = _presenter.MoveToTransformAndKill(syncTr.GetTransform(), 0.6f);
		}

		public TeamType GetTeam() {
			return Team;
		}

		public override void Tick(float currentTime, float deltaTime) {
			base.Tick(currentTime, deltaTime);	
			if ( !IsServer || !IsEntityAlive || SelfDestructTime < 0 ) {
				return;
			}
			if ( currentTime - _setupTime > SelfDestructTime ) {
				DestroyEntity();
			}
		}

		public override void ApplyFullState(EntityState state) {
			base.ApplyFullState(state);
			var cast = (CargoContainerState)state;
			if ( cast != null ) {
				Setup(cast.Inventory);
			} else {
				Setup(new List<BaseInventoryItem>());
			}
		}

		protected override CargoContainerState SaveInternal() {
			var state = base.SaveInternal();
			state.Inventory = _inventory;
			state.CreatorId = CreatorID;
			return state;
		}

		protected override string CreateSummary() {
			return $"type:cargo,slots:{_inventory.OccupiedSlotsCount},count:{_inventory.ItemCount},price:{_inventory.GetWholeInventoryPrice()}";
		}
	}
}